home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
s48.zip
/
USER-GUI.TXT
< prev
Wrap
Lisp/Scheme
|
1992-07-03
|
16KB
|
482 lines
A line may take us hours, yet if it does not seem a moment's thought
All our stitching and unstitching has been as nought.
Yeats
Adam's Curse
Random notes on the Scheme48 system.
-----
Introduction
Scheme48 is an implementation of the Scheme programming language as
described in the Revised^4 Report on the Algorithmic Language Scheme.
It is based on a compiler and interpreter for a virtual Scheme
machine. The name derives from our desire to have an implementation
that is simple and lucid enough that it looks as if it were written in
just 48 hours. We don't claim to have reached that stage yet; much
more simplification is necessary.
Scheme48 tries to be faithful to the Revised^4 Report, providing
neither more nor less in the initial user environment. (This is not
to say that more isn't available in other environments; see below.)
Support for numbers is weak: bignums are slow and floating point is
nonexistent. DEFINE-SYNTAX and SYNTAX-RULES are supported, but not
the rest of the Revised^4 Scheme macro proposal.
Departing a bit from the Report, Scheme48 enforces one restriction
from the IEEE 1178-1990 Scheme Standard: before being able to SET! a
built-in variable like CONS or LOAD, you must DEFINE it first.
This is what might be called an alpha release. Please report bugs,
especially in the VM, especially core dumps, to
scheme48-bugs@altdorf.ai.mit.edu. It is a goal of this project to produce
a bullet-proof system; we want no bugs and, especially, no crashes.
(There are a few known bugs, listed in the TODO file that comes with
the distribution.)
-----
Command line arguments
s48 [-i image] [-h heapsize] [-a argument]
-i image
specifies a heap image file to resume (heap images are created by
the :dump and :build commands). This defaults to a heap image
that runs a Scheme "command processor."
-h heapsize
specifies how much space should be reserved for allocation.
Heapsize is in bytes, and covers both semispaces for the copying
GC. Cons cells are currently 12 bytes, so if you want to make
sure you can allocate a million cons cells, you should specify -h
24000000 (actually more than this, to account for the initial heap
image and breathing room).
-a argument
is only useful with images built using :build. argument is passed
as a string to the procedure specified in the :build command. E.g.
> :build (lambda (a) (display a) (newline)) foo.image
> :exit
% scheme48vm -i foo.image -a mumble
mumble
%
-----
Editing
We recommend running Scheme48 under emacs using "cmuscheme." Can't
tell you how to get emacs, but cmuscheme is available by anonymous ftp
from ftp.cs.cornell.edu: pub/jar/cmu.tar. Put these forms in your
emacs init file:
(setq scheme-program-name "s48") ;or whatever scheme48 is installed as
(autoload 'run-scheme "cmuscheme" "Run an inferior Scheme process." t)
You will probably also need to put the directory containing cmuscheme
and related files in your emacs load-path:
(setq load-path (append load-path <directory>))
For futher documentation see cmuscheme.el and comint.el.
-----
Benchmark mode
If you want to run benchmarks, or just generally have your code run
faster than it normally would, enter "benchmark mode" before loading
anything. Otherwise calls to primitives (like + and cons) won't be
inlined, and programs will run more slowly. Enter benchmark mode by
issuing the :bench command to the command processor.
The system doesn't start in benchmark mode by default because the
Scheme report permits redefinitions of built-in procedures. In
benchmark mode, such redefinitions don't work quite right, because
previously compiled programs will use the byte codes for primitives
instead of calling through variable's location.
-----
Inspector
There is a low-tech inspector, available via the :inspect and :debug
commands. The :inspect command starts an inspector command loop.
There is a "current object", for which a menu of selectable components
is displayed. To inspect that component, just type the number. For
example:
:inspect '(a (b c) d)
(a (b c) d)
[0] a
[1] (b c)
[2] d
inspect: 1
(b c)
[0] b
[1] c
inspect:
Other inspector commands:
q quit
u pop object stack
d down stack (current object must be a continuation)
m print more of a long menu
dis print a disassembly of current object (which must be a
closure, continuation, or template)
tem go to a closure or continuation's template
(...) evaluate a form
The inspector sets ## to be the object currently being inspected.
After an error occurs, :debug invokes the inspector on the
continuation at the point of the error. The U and D (up and down)
commands then make the inspector look like a conventional stack
debugger, with continuationspalying the role of stack frames. D goes
to older or deeper continuations (frames), and U goes back up to more
recent ones.
-----
Disassembler
The :dis command disassembles procedures. Also available as the "dis"
command in the inspector.
> :dis cons
(lap cons
0 (check-nargs= 2)
2 (make-env 2)
4 (local 0 2)
7 (push)
8 (local 0 1)
11 (cons)
12 (return))
>
The disassembler can also be invoked on continuations and templates.
Templates are the static components of procedures; these are found
inside of procedures and continuations, and look like vectors that
have code vectors as their zeroth component.
-----
Package system
[Jun 1992: I bit the bullet and wrote a little module system for
scheme48. Tried to make it as concise and featureless as possible.
To avoid confusion with Scheme Xerox's module system I have called it
a "package" system (which KMP won't like one bit). Here's a brief
description in very operational terms. I won't say it's useable in
this form -- a few other things might be required, like some kind of
:load-package command that exploits an association between packages
and files. And the implementation is bound to be buggy, especially in
the realm of forward reference adjustments (retroactive shadwoing and
exports). Comments welcome. -Jonathan]
The package system is superficially like the Common Lisp package
system, except that it controls the mapping of names to denotations
instead of the mapping of string to symbols. (A name is represented
internally as a symbol; a denotation is either a variable location,
syntactic operator, or a package.) Packages, like macros, are
second-class. They are created with the DEFINE-PACKAGE special form,
and accessed in one of two ways: by the PACKAGE-REF special form, or
by being "opened" in a DEFINE-PACKAGE.
DEFINE-PACKAGE works like this:
<definition> ::= (define-package <name> <clause> ...)
where
<clause> ::= (access <name> ...)
| (open <name> ...)
| (export <name> ...)
| (file <name> ...)
An OPEN clause specifies which packages will be opened up for use
inside the new package (like USE-PACKAGE in Common Lisp). At least
one package must be specified or else it will be impossible to write
any useful programs inside the package, since DEFINE, LAMBDA, CONS,
PACKAGE-REF, etc. will be unavailable. Typical packages to list in
the OPEN clause are SCHEME (which exports Revised^4 Scheme) and
DEFPACKAGE (which exports PACKAGE-REF and DEFINE-PACKAGE). There are
some other initial packages as well; see below.
An ACCESS clause specifies which package names will be carried into
the package. This allows use of a package via PACKAGE-REF or
DEFPACKAGE without opening up the package. If a package name isn't
listed in an OPEN or ACCESS clause, and is not defined internal to a new
package via another DEFINE-PACKAGE, then that package will not be
valid in a PACKAGE-REF or DEFINE-PACKAGE. If a package ACCESSes any
other packages, it should probably also OPEN the DEFPACKAGE package so
that PACKAGE-REF itself is available.
An EXPORT clause specifies names that are to be defined in this
package and made accessible outside of the package (via another OPEN or
ACCESS and PACKAGE-REF).
FILE clauses are currently ignored.
PACKAGE-REF has the following syntax:
<expression> ::= (package-ref <name1> <name2>)
<name1> must be the name of a package, and <name2> must be something
that the package exports.
An imported binding may be lexically overridden or "shadowed" simply
by doing a DEFINE (or DEFINE-SYNTAX or DEFINE-PACKAGE) of the name
whose binding is to be shadowed. This will create a new binding
without having any effect on the binding in the opened package. For
example, in the USER package one can do (DEFINE CAR 'CHEVY) without
affecting the binding of the name CAR in the SCHEME package.
It is an error to assign (SET!) a variable except in the package that
defines it. (Unfortunately, the implementation doesn't currently
enforce this restriction. The restriction is necessary in order to
make module compilation, also currently unimplemented, semantically
sound.)
The command processor supports the package system with several special
commands. For these commands, package names are resolved in a package
called the PACKAGES package.
- :set-package package-name moves the command processor inside a
specified package. E.g.
:set-package user
moves into the user initial package (which is the binding of the
name USER in the PACKAGES package).
The command processor displays the name of the current package in
the prompt, unless the current package is the user package.
- The :load-into command loads one or more files into a specified
package.
:load-into package file1 file2 ...
is similar to :set-package package followed by :load file1 file2
..., except that the current package ends up being unchanged.
- The :new-package command creates a new package.
:new-package name open1 open2 ...
is short for the sequence
> :set-package packages
packages> (define-package name (open open1 open2 ... scheme))
packages> :set-package name
name>
- :export name1 name2 ... causes the indicated names to be exported
from the current package, as if they had been listed in the EXPORT
clause of the DEFINE-PACKAGE form that created the current package.
- :open-package name1 name2 ...
- :clear-package name undoes any definitions that have been made in
the indicated package.
[There probably also ought to be a :access command.]
Predefined packages: the following are initially defined (in the
PACKAGES package):
scheme -- exports Revised^4 Scheme: LAMBDA, QUOTE, CONS, etc.
user -- the user initial package (command processor indicates
that this is current with a simple "> " prompt). This doesn't
export any bindings, so it doesn't make sense to OPEN or ACCESS
it, only to :load-into or :set-package to it. Opens only the
scheme package.
:disable is the same as :set-package user.
defpackage -- exports DEFINE-PACKAGE, PACKAGE-REF, SCHEME, and
DEFPACKAGE.
table -- hash tables
record -- record types
enumerated -- enumerated types
packages -- opens scheme and defpackage; no exports.
primitives -- exports Scheme48 virtual machine primitives.
See rts/reflect.scm for a list. Some of these primitives do
no error checking, and improper use may crash the system.
The primitives package doesn't export things like
CAR that are already exported by the SCHEME package (this may
be a design error? may change).
system -- exports all kinds of stuff; highly unstable. See
rts/reflect.scm for a list.
:enable is the same as :set-package system.
for-syntax -- the package in which <expression> in
(define-syntax <name> <expression>) is evaluated.
No exports.
-----
LOAD
The load procedure exported by the scheme package takes an optional
second argument that, if supplied, should be the package into which
the file named by its first argument should be loaded. If not
supplied, load loads the file into the package that is the current
value of (fluid $package-for-load). Packages may be obtained for this
purpose as first-class Scheme values by using the get-package
procedure, which looks up a package name in the packages package.
fluid, $package-for-load, and get-package are all exported by the
system package.
Whether the package argument is supplied or not, load binds (using
let-fluid) $package-for-load to the package into which the file is
loaded. $package-for-load is also set (using set-fluid!) by the
command processor's :set-package and :new-package commands.
-----
access-scheme48
A simpler way to get at features that are ordinarily hidden inside the
the system or primitives packages is the "access-scheme48" procedure,
which is exported by the scheme package. (access-scheme48 'name) is
similar to (package-ref system name), except that name need not be
exported by the system package. E.g.
(define make-fluid (access-scheme48 'make-fluid))
(define fluid (access-scheme48 'fluid))
will copy the values of the variables make-fluid and fluid to the user
package. But it's better style to use the package system; run any
program requiring these bindings in a package that uses the defpackage
package and accesses the system package.
-----
Library
There are some useful libraries in the "misc" subdirectory of the
distribution. Before using many of these it is necessary to load the
appropriate package definitions:
> :load-into packages misc/package-defs.scm
pp.scm
A pretty-printer. (p <exp>) will pretty-print the result of <exp>,
which must be an S-expression. (Source code for procedures is not
retained or reconstructed.)
The procedure pretty-print takes three arguments: the object to be
printed, a port to write to, and the current horizontal cursor
position. If you've just done a newline, then pass in zero for
the position argument.
The algorithm is very peculiar, and sometimes buggy.
> :load-into pp misc/pp.scm
> :open-package pp
random.scm
Random number generator.
> :load-into random misc/random.scm
> :open-package random
> (define random (make-random <seed>))
> (random) => a pseudo-random number between 0 and 2^28
sort.scm
Online merge sort (see comment at top of file)
(sort-list <list> <pred>)
(sort-list! <list> <pred>)
tokenize.scm
Defines lexical utilities (something like "read tables" in Common
Lisp).
pratt.scm
An infix parser shell (courtesy Paradigm Associates, Inc.). Needs
tokenize.scm.
sgol.scm
An example use of pratt.scm. See top of file for description.
sicp.scm
Compatibility for "Structure & Interpretation of Computer Programs."
Just load it into the user package.
queue.scm
FIFO queues.
defrecord.scm
A define-record-type macro, providing more concise use of the
record package.
format.scm
A simple FORMAT procedure, similar to Common Lisp's or T's.
receive.scm
Multiple value returns.
bigbit.scm
Extensions to the bitwise logical operators (exported by
the primitives package) so that they operate on bignums.
> :load-into system bigbit.scm
xport.scm, new-ports.scm
Ports for reading from and writing to strings, and related things.
Documentation pending.
assem.scm
An assembler for the virtual machine.
> :load-into system misc/assem.scm
> :open-package assembler
> ((%lap foo (literal '1) (return)))
1
thread.scm
A multitasking subsystem. Needs queue.scm, compose-cont.scm, and
bindings from the system and primitives packages.
> :load-into queue misc/queue.scm
misc/queue.scm ..................
> :load-into thread misc/compose-cont.scm misc/thread.scm
misc/compose-cont.scm ..
misc/thread.scm ...............................................
> :open-package thread
> (start-multitasking (simple-thread-condition-handler))
0
> (define (foo) (display "hi") (newline) (relinquish-timeslice) (foo))
> (define th (spawn foo 'foo))
hi
> 12
hi
12
> (kill-thread th)
hi
#t
>
Task switching is preemptive, except that input (read-char) is not
interrupted.
compose-cont.scm
Hack needed for threads package.
sleep.scm
A SLEEP procedure, to be used with the threads package.
> :load-into thread misc/sleep.scm
This will busy-wait if there's nothing else to do, so it's not
advisable under time-sharing.
-----
Acknowledgment
Thanks to Deborah Tatar for providing the Yeats quotation.